package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gitee.com/zhouli1369/go2struct/internal/dto"
	"gitee.com/zhouli1369/go2struct/internal/service"
	"gitee.com/zhouli1369/go2struct/internal/utils"
	"gorm.io/gorm"
	"html/template"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

// Dbo 数据库链接
var Dbo *gorm.DB

// go run main.go mysql "root:123456@(127.0.0.1:3306)/emis?charset=utf8" ./tpl/gorm-mysql.tpl ./models
// go run main.go postgre "root:123456@(127.0.0.1:3306)/emis?charset=utf8" ./tpl/gorm-postgre.tpl ./models
func main() {
	// 1、申明参数
	cmdParam := dto.CmdParam{}

	// 2、获取参数,第0个参数是exe的路径
	if len(os.Args) < 4 {
		fmt.Println("命令参数不全！！")
		return
	} else {
		cmdParam.Driver = os.Args[1]
		cmdParam.Dsn = os.Args[2]
		cmdParam.TplRelPath = os.Args[3]
		if len(os.Args) > 4 {
			// 解析go文件路径
			cmdParam.GoRelPath = os.Args[4]
		}
		// 解析dsn获取到数据库名
		cmdParam.DbName = utils.DsnAnalysisDbName(cmdParam.Driver, cmdParam.Dsn)
		// 获取模版文件的绝对路径
		cmdParam.TplAbsPath, _ = filepath.Abs(cmdParam.TplRelPath)
		// 获取要生成的文件绝对路径
		cmdParam.GoAbsPath, _ = filepath.Abs(cmdParam.GoRelPath)
		// 获取go结构体命名空间,注意：path.Base不能解析windows下的“\”，需要替换为“/”
		cmdParam.GoNameSpace = path.Base(strings.Replace(cmdParam.GoAbsPath, "\\", "/", -1))

		// 打印输出参数配置
		jsonData, _ := json.Marshal(cmdParam)
		fmt.Println("command params:")
		fmt.Println(string(jsonData))
	}
	// 3、创建数据库工厂类
	factory := &service.DbFactory{}
	strategy, err := factory.CreateStrategy(cmdParam)
	if err != nil {
		panic(err)
	}
	// 4、查询数据库信息
	dbInfo, err := strategy.QueryDataInfo()
	//fmt.Println("dbInfo2", dbInfo)

	if err != nil {
		fmt.Println("Query DataBase Exception:")
		fmt.Println(err.Error())
		return
	}
	//
	tplBytes, err := ioutil.ReadFile(cmdParam.TplAbsPath)
	if err != nil {
		fmt.Println("读取模板文件错误:", err)
		return
	}
	//模板文件字符串
	tplStr := string(tplBytes)
	//fmt.Println(tplStr)

	//new 模板，命名temHtml
	tplFile, _ := template.New("temHtml").Parse(tplStr)

	//判断文件夹是否存在，不存在才创建
	_, err = os.Stat(cmdParam.GoAbsPath)
	if err != nil || os.IsNotExist(err) {
		//创建多级目录
		err := os.MkdirAll(cmdParam.GoAbsPath, os.ModePerm)
		if err != nil {
			fmt.Println("创建go文件目录错误:", err)
			return
		}
		fmt.Println("> Folder does not exist, created!!")
	} else {
		fmt.Println("> The folder already exists.")
	}

	//生成之前先删除原来的文件
	//delDir, err := ioutil.ReadDir(cmdParam.GoAbsPath)
	//for _, d := range delDir {
	//	os.RemoveAll(path.Join([]string{cmdParam.GoAbsPath, d.Name()}...))
	//}

	//遍历表,生成实体并覆盖文件
	for i, table := range dbInfo.DbTables {
		fmt.Println(i+1, "/", len(dbInfo.DbTables), table.TableName)
		// if i > 0 {
		// 	break
		// }
		//根据模板生成最终数据
		buf := new(bytes.Buffer)
		tplFile.Execute(buf, table)
		//fmt.Println(buf.String())
		//生成go文件路径
		currFile := path.Join(cmdParam.GoAbsPath, fmt.Sprintf("%s%s", table.GoName, ".go"))
		f, err := os.Create(currFile)
		defer f.Close()
		if err == nil {
			//保存文件
			f.Write([]byte(buf.String()))
		} else {
			fmt.Println(err)
		}
	}
	formatGoFile(cmdParam.GoAbsPath)
}

// formatGoFile 格式化go文件
func formatGoFile(goFilePath string) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	goFilePath = strings.Replace(goFilePath, "\\", "/", -1)
	//命令不认识window下的"\"符号，需要转换成"/"
	cmdStr := fmt.Sprintf("gofmt -l -w -s %s", goFilePath)
	fmt.Println(cmdStr)
	cmd := exec.Command("sh", "-c", cmdStr)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		fmt.Println("format go file failed!")
	} else {
		fmt.Println("format go file success!")
	}
}
